package com.anlia.progressbar;

import com.anlia.utils.AttrUtils;
import com.anlia.utils.DpOrPxUtils;

import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.components.Text;
import ohos.agp.render.*;
import ohos.agp.utils.Color;
import ohos.app.Context;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.media.image.PixelMap;
import ohos.media.image.common.PixelFormat;
import ohos.media.image.common.Size;

/**
 * Created by anlia on 2017/10/16.
 */
public class WaveProgressView extends Component implements Component.DrawTask,
        Component.EstimateSizeListener, AnimatorValue.ValueUpdateListener {
    private static final int TWO = 2;
    private Paint circlePaint; // 圆形进度框画笔
    private Paint wavePaint; // 绘制波浪画笔
    private Path wavePath; // 绘制波浪Path
    private Paint secondWavePaint; // 绘制第二个波浪的画笔
    private PixelMap pixelMap;
    private Canvas bitmapCanvas;
    private AnimatorValue waveProgressAnim;
    private Text text;
    private OnAnimationListener onAnimationListener;

    private float waveWidth; // 波浪宽度
    private float waveHeight; // 波浪高度
    private int waveNum; // 波浪组的数量（一次起伏为一组）
    private float waveMovingDistance; // 波浪平移的距离

    private int viewSize; // 重新测量后View实际的宽高
    private int defaultSize; // 自定义View默认的宽高

    private float percent; // 进度条占比
    private float progressNum; // 可以更新的进度条数值
    private float maxNum; // 进度条最大值

    private Color waveColor; // 波浪颜色
    private Color secondWaveColor; // 第二层波浪颜色
    private Color bgColor; // 背景进度框颜色
    private boolean isDrawSecondWave;
    private float mPlan;
    private int mTime;
    private EventHandler eventHandler = new EventHandler(EventRunner.getMainEventRunner());

    /**
     * 构造
     *
     * @param context 上下文
     */
    public WaveProgressView(Context context) {
        this(context, null);
    }

    /**
     * 构造
     *
     * @param context 上下文
     * @param attrSet 属性集
     */
    public WaveProgressView(Context context, AttrSet attrSet) {
        super(context, attrSet);
        addDrawTask(this);
        setEstimateSizeListener(this);
        init(context, attrSet);
    }

    private void init(Context context, AttrSet attrSet) {
        waveWidth = AttrUtils.getDimensionPixelSize(attrSet, "wave_width", DpOrPxUtils.dip2px(context, 25));
        waveHeight = AttrUtils.getDimensionPixelSize(attrSet, "wave_height", DpOrPxUtils.dip2px(context, 5));
        waveColor = AttrUtils.getColor(attrSet, "wave_color", Color.GREEN);
        secondWaveColor = AttrUtils.getColor(attrSet, "second_wave_color", new Color(Color.getIntColor("#800de6e8")));
        bgColor = AttrUtils.getColor(attrSet, "wave_bg_color", Color.GRAY);
        defaultSize = DpOrPxUtils.dip2px(context, 100);
        waveNum = (int) Math.ceil(Double.parseDouble(String.valueOf(defaultSize / waveWidth / 2)));
        waveMovingDistance = 0;

        wavePath = new Path();

        wavePaint = new Paint();
        wavePaint.setColor(waveColor);
        wavePaint.setAntiAlias(true); // 设置抗锯齿
        wavePaint.setBlendMode(BlendMode.SRC_IN);

        secondWavePaint = new Paint();
        secondWavePaint.setColor(secondWaveColor);
        secondWavePaint.setAntiAlias(true); // 设置抗锯齿
        secondWavePaint.setBlendMode(BlendMode.SRC_ATOP); // 因为要覆盖在第一层波浪上，且要让半透明生效，所以选此模式

        circlePaint = new Paint();
        circlePaint.setColor(bgColor);
        circlePaint.setAntiAlias(true); // 设置抗锯齿
        percent = 0;
        progressNum = 0;
        maxNum = 100;
        isDrawSecondWave = false;
    }

    @Override
    public void onDraw(Component component, Canvas canvas) {
        if (percent < progressNum / maxNum) {
            percent = mPlan * progressNum / maxNum;
            if (text != null && onAnimationListener != null) {
                text.setText(onAnimationListener.howToChangeText(mPlan, progressNum, maxNum));
            }
        }
        waveMovingDistance = mPlan * waveNum * waveWidth * TWO;
        pixelMap = createPixelMap();
        Texture texture = new Texture(pixelMap);
        bitmapCanvas = new Canvas(texture);
        bitmapCanvas.drawCircle((float) viewSize / TWO, (float) viewSize / TWO, (float) viewSize / TWO, circlePaint);
        bitmapCanvas.drawPath(getWavePath(), wavePaint);
        if (isDrawSecondWave) {
            bitmapCanvas.drawPath(getSecondWavePath(), secondWavePaint);
        }
        PixelMapHolder pixelMapHolder = new PixelMapHolder(pixelMap);
        canvas.drawPixelMapHolder(pixelMapHolder, 0, 0, circlePaint);
    }

    private PixelMap createPixelMap() {
        PixelMap.InitializationOptions options = new PixelMap.InitializationOptions();
        options.size = new Size(viewSize, viewSize);
        options.pixelFormat = PixelFormat.ARGB_8888;
        options.editable = true;
        pixelMap = PixelMap.create(options);
        return pixelMap;
    }

    private Path getSecondWavePath() {
        float changeWaveHeight = waveHeight;
        if (onAnimationListener != null) {
            changeWaveHeight =
                    onAnimationListener.howToChangeWaveHeight(percent, waveHeight) == 0 && percent < 1
                            ? waveHeight
                            : onAnimationListener.howToChangeWaveHeight(percent, waveHeight);
        }

        wavePath.reset();

        // 移动到左上方，也就是p3点
        wavePath.moveTo(0, (float) ((double) 1 - percent) * viewSize);

        // 移动到左下边，也就是p2点
        wavePath.lineTo(0, viewSize);

        // 移动到右下方，也就是p1点
        wavePath.lineTo(viewSize, viewSize);

        // 移动到右上方，也就是p0点
        wavePath.lineTo(viewSize + waveMovingDistance, (float) ((double) 1 - percent) * viewSize);

        // 从p0开始向p3方向绘制波浪曲线
        for (int ij = 0; ij < waveNum * TWO; ij++) {
            wavePath.rQuadTo(-waveWidth / TWO, changeWaveHeight, -waveWidth, 0);
            wavePath.rQuadTo(-waveWidth / TWO, -changeWaveHeight, -waveWidth, 0);
        }

        // 将path封闭起来
        wavePath.close();
        return wavePath;
    }

    private Path getWavePath() {
        float changeWaveHeight = waveHeight;
        if (onAnimationListener != null) {
            changeWaveHeight =
                    onAnimationListener.howToChangeWaveHeight(percent, waveHeight) == 0 && percent < 1
                            ? waveHeight
                            : onAnimationListener.howToChangeWaveHeight(percent, waveHeight);
        }

        wavePath.reset();

        // 移动到右上方，也就是p0点
        wavePath.moveTo(viewSize, (1 - percent) * viewSize);

        // 移动到右下方，也就是p1点
        wavePath.lineTo(viewSize, viewSize);

        // 移动到左下边，也就是p2点
        wavePath.lineTo(0, viewSize);

        // 移动到左上方，也就是p3点
        wavePath.lineTo(-waveMovingDistance, (1 - percent) * viewSize);

        // 从p3开始向p0方向绘制波浪曲线
        for (int ii = 0; ii < waveNum * TWO; ii++) {
            wavePath.rQuadTo(waveWidth / TWO, changeWaveHeight, waveWidth, 0);
            wavePath.rQuadTo(waveWidth / TWO, -changeWaveHeight, waveWidth, 0);
        }

        // 将path封闭起来
        wavePath.close();
        return wavePath;
    }

    @Override
    public boolean onEstimateSize(int width, int height) {
        int mHeight = measureSize(defaultSize, height);
        int mWidth = measureSize(defaultSize, width);
        int min = Math.min(mWidth, mHeight); // 获取View最短边的长度
        setEstimatedSize(min, min);
        viewSize = min;
        waveNum = (int) Math.ceil(Double.parseDouble(String.valueOf(viewSize / waveWidth / 2)));
        return false;
    }

    @Override
    public void onUpdate(AnimatorValue animatorValue, float value) {
        mPlan = value;
        invalidate();
        if (value == 1.0) {
            eventHandler.postTask(new Runnable() {
                @Override
                public void run() {
                    setProgressNum(progressNum, mTime);
                    invalidate();
                }
            }, TWO);
        }
    }

    public interface OnAnimationListener {
        /**
         * 如何处理要显示的文字内容
         *
         * @param interpolatedTime 从0渐变成1,到1时结束动画
         * @param updateNum 进度条数值
         * @param maxNum 进度条最大值
         * @return 进度
         */
        String howToChangeText(float interpolatedTime, float updateNum, float maxNum);

        /**
         * 如何处理波浪高度
         *
         * @param percent 进度占比
         * @param waveHeight 波浪高度
         * @return 高度
         */
        float howToChangeWaveHeight(float percent, float waveHeight);
    }

    public void setOnAnimationListener(OnAnimationListener onAnimationListener) {
        this.onAnimationListener = onAnimationListener;
    }

    private int measureSize(int size, int measureSpec) {
        int result = defaultSize;
        int specMode = EstimateSpec.getMode(measureSpec);
        int specSize = EstimateSpec.getSize(measureSpec);

        if (specMode == EstimateSpec.PRECISE) {
            result = specSize;
        } else if (specMode == EstimateSpec.NOT_EXCEED) {
            result = Math.min(result, specSize);
        }
        return result;
    }

    /**
     * 设置进度数值
     *
     * @param num 进度
     * @param time 时间
     */
    public void setProgressNum(float num, int time) {
        this.progressNum = num;
        this.mTime = time;
        percent = 0;
        if (waveProgressAnim == null) {
            waveProgressAnim = new AnimatorValue();
            waveProgressAnim.setDuration(time);
            waveProgressAnim.setCurveType(Animator.CurveType.INVALID);
            waveProgressAnim.setValueUpdateListener(this);
            waveProgressAnim.start();
        } else {
            waveProgressAnim.start();
        }
    }

    /**
     * 是否绘制第二层波浪
     *
     * @param isDeck true 是，反之
     */
    public void setDrawSecondWave(boolean isDeck) {
        this.isDrawSecondWave = isDeck;
    }

    /**
     * 设置字体
     *
     * @param text 进度
     */
    public void setText(Text text) {
        this.text = text;
    }
}
